package sicnu.cs.ich.security.security.rest;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import sicnu.cs.ich.api.domain.form.WechatUserForm;
import sicnu.cs.ich.security.exceptions.exception.WechatLoginException;
import sicnu.cs.ich.security.security.token.WechatAuthenticationToken;
import sicnu.cs.ich.security.util.WxUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;


/**
 * @author 沈洋 邮箱:1845973183@qq.com
 * @create 27-06-2021-21:11
 **/
@Slf4j
public class WechatAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    //private final RequestMatcher requiresAuthenticationRequestMatcher = new AntPathRequestMatcher("/wechatLogin", "POST");
    //;

    public static final String WECHAT_USER_FORM = "wechatUserForm";
    // ~ Static fields/initializers
    // =====================================================================================
    //需要传入微信获取的code
    public static final String WECHAT_CODE = "wechatCode";
    public static final String WECHAT_NICK_NAME = "nickname";
    public static final String WECHAT_AVATAR_URL = "avatarUrl";
    public static final String WECHAT_GENDER = "gender";
    //private String wechatParameter = WECHAT_FORM_USERNAME_KEY;

    // ~ Constructors
    // ===================================================================================================
    //要匹配的登录请求
    public WechatAuthenticationFilter(String loginPath) {
        super(new AntPathRequestMatcher(loginPath, "POST"));
        //super.setAuthenticationManager(authenticationManager);
    }

    // ~ Methods
    // ========================================================================================================

    public Authentication attemptAuthentication(HttpServletRequest request,
                                                HttpServletResponse response) throws AuthenticationException {
        // 只允许Post方式登录
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException(
                    "Authentication method not supported: " + request.getMethod());
        }
        // 取出WechatCode
        WechatUserForm userForm = null;
        try (InputStream inputStream = request.getInputStream()){
            JsonNode jsonNode = new ObjectMapper().readTree(inputStream);
            // 校验是否具有所有信息
            if (!jsonNode.has(WECHAT_CODE)||!jsonNode.has(WECHAT_NICK_NAME)
                    ||!jsonNode.has(WECHAT_GENDER)||!jsonNode.has(WECHAT_AVATAR_URL)){
                throw new BadCredentialsException("用户参数不全");
            }
            //var openId = jsonNode.get(WECHAT_CODE).textValue();
            var openId = obtainWechatOpenId(jsonNode.get(WECHAT_CODE).textValue());
            userForm = WechatUserForm.builder()
                    .openId(openId)
                    .nickname(jsonNode.get(WECHAT_NICK_NAME).textValue())
                    .gender(jsonNode.get(WECHAT_GENDER).intValue()==0?0:1)
                    .avatarUrl(jsonNode.get(WECHAT_AVATAR_URL).textValue())
                    .build();
            //request.setAttribute(WECHAT_USER_FORM,userForm);
        }catch (IOException ex){
            log.error("数据无法解析");
            throw new WechatLoginException(
                    "JSON无法解析");
        }
        // 放入Token中
        WechatAuthenticationToken authRequest = new WechatAuthenticationToken(userForm);
        // Allow subclasses to set the "details" property
        setDetails(request, authRequest);
        return this.getAuthenticationManager().authenticate(authRequest);
    }



    /**
     * Provided so that subclasses may configure what is put into the authentication
     * request's details property.
     *
     * @param request     that an authentication request is being created for
     * @param authRequest the authentication request object that should have its details
     *                    set
     */
    protected void setDetails(HttpServletRequest request,
                              WechatAuthenticationToken authRequest) {
        authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
    }


    /**
     * 获取微信openId
     * @return openId
     */
    protected String obtainWechatOpenId(String wechatCode) throws WechatLoginException {
        Map<String, Object> result = WxUtils.wechatLoginByCode(wechatCode);
        String openId = (String) result.get("openid");
        if (openId != null) {
            log.info("登陆成功,openid为"+openId);
            return openId;
        } else {
            log.info("登陆失败");
            throw new WechatLoginException("code异常");
        }
    }

}